﻿using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Fall.Core.BaseModels.EFModels;
using Fall.Core.Reflaction;
using System;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace Fall.EntityFrameworkCore
{
    public abstract class FallDbContext<TDbContext> : DbContext where TDbContext : DbContext
    {
        protected FallDbContext(DbContextOptions<TDbContext> options)
            : base(options)
        {

        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
        }
        public override int SaveChanges()
        {
            ApplyConcepts();
            return base.SaveChanges();
        }

        public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
        {
            ApplyConcepts();
            return base.SaveChangesAsync(cancellationToken);
        }

        protected virtual void ApplyConcepts()
        {
            foreach (var entry in ChangeTracker.Entries().ToList())
            {
                ApplyConcepts(entry);
                SetOtherConcepts(entry);
            }
        }

        protected virtual void SetOtherConcepts(EntityEntry entry) { }

        protected virtual void ApplyConcepts(EntityEntry entry)
        {
            switch (entry.State)
            {
                case EntityState.Added:
                    ApplyConceptsForAddedEntity(entry);
                    break;
                case EntityState.Modified:
                    ApplyConceptsForModifiedEntity(entry);
                    break;
                case EntityState.Deleted:
                    ApplyConceptsForDeletedEntity(entry);
                    if (entry.Entity is ISoftDeleteEntity) entry.State = EntityState.Modified;
                    break;
            }
        }

        protected virtual void ApplyConceptsForAddedEntity(EntityEntry entry)
        {
            CheckAndSetId(entry);
            SetCreationAuditProperties(entry);
        }

        protected virtual void SetCreationAuditProperties(EntityEntry entry)
        {
            SetCreation(entry.Entity);

        }

        protected virtual void SetCreation(object entity)
        {
            if (entity is ICreationTimeEntity creationTimeEntity)
            {
                if (creationTimeEntity.CreationTime == default)
                {
                    ObjectHelper.TrySetProperty(creationTimeEntity, x => x.CreationTime, () => DateTime.Now);
                }
                if (creationTimeEntity.CreationUserId == default)
                {
                    //Todo
                }
            }
        }

        #region 设置ID
        protected virtual void CheckAndSetId(EntityEntry entry)
        {
            if (entry.Entity is IEntity<Guid> entity)
            {
                TrySetGuidId(entry, entity);
            }
        }

        protected virtual void TrySetGuidId(EntityEntry entry, IEntity<Guid> entity)
        {
            if (entity.Id != default)
            {
                return;
            }
            var idProperty = entry.Property("Id").Metadata.PropertyInfo;
            var dbGeneratedAttr = ReflactionHelper
                .GetSingleAttributeOrDefault<DatabaseGeneratedAttribute>(
                    idProperty
                );
            if (dbGeneratedAttr != null && dbGeneratedAttr.DatabaseGeneratedOption != DatabaseGeneratedOption.None)
            {
                return;
            }
            EntityHelper.TrySetId(
                entity,
                () => Guid.NewGuid());
        }

        #endregion

        protected virtual void ApplyConceptsForModifiedEntity(EntityEntry entry)
        {
            SetModified(entry.Entity);
        }
        /// <summary>
        /// 设置修改人和修改时间
        /// </summary>
        /// <param name="entity"></param>
        protected virtual void SetModified(object entity)
        {
            if (entity is IModifyTimeEntity modifyTimeEntity)
            {
                if (modifyTimeEntity.ModifyTime == default || null == modifyTimeEntity.ModifyTime)
                {
                    ObjectHelper.TrySetProperty(modifyTimeEntity, x => x.ModifyTime, () => DateTime.Now);
                }
                if (modifyTimeEntity.ModifyUserId == default)
                {
                    //Todo
                }
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="entry"></param>
        protected virtual void ApplyConceptsForDeletedEntity(EntityEntry entry)
        {
            SetDeleted(entry.Entity);
        }
        /// <summary>
        /// 设置删除时间，删除人
        /// </summary>
        /// <param name="entity"></param>
        protected virtual void SetDeleted(object entity)
        {
            if (entity is ISoftDeleteEntity softDeleteEntity)
            {
                if (softDeleteEntity.DeletedTime == default || null == softDeleteEntity.DeletedTime)
                {
                    ObjectHelper.TrySetProperty(softDeleteEntity, x => x.DeletedTime, () => DateTime.Now);
                }
                softDeleteEntity.IsDeleted = true;
                //ToDo deletedUserId
            }
        }
    }
}
